package org.common.utils.net.netty;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import org.common.utils.net.netty.core.NettyInitializer;
import org.common.utils.thread.DefaultThreadFactory;
import org.common.utils.thread.ThreadTool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 基于Netty4的服务端
 * @author zhouzhibing
 * @date 2025/11/13 12:47
 */
public class NettyServer {

    private static final Logger log = LoggerFactory.getLogger(NettyServer.class);
    private static final boolean SSL = System.getProperty("ssl") != null;
    private ServerBootstrap bootstrap;

    /**
     * boss线程组 , worker线程组
     */
    private EventLoopGroup bossGroup , workerGroup;
    /**
     * Netty配置
     */
    private NettyInitializer initializer;
    /**
     * 服务器channel
     */
    private Channel serverChannel;

    public NettyServer(NettyInitializer initializer) {
        this.initializer = initializer;
    }

    /**
     * 启动服务
     * @param port 端口
     */
    public void start(int port) {
        int cpuCount = ThreadTool.getCpuCount();
        try {
            ChannelFutureListener remover = new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                    future.sync();
                }
            };

//            final SslContext sslCtx;
//            if (SSL) {
//                SelfSignedCertificate ssc = new SelfSignedCertificate();
//                sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
//            } else {
//                sslCtx = null;
//            }

            this.bossGroup = new NioEventLoopGroup(cpuCount , new DefaultThreadFactory(initializer.getName() + "-NettyServer-BossGroup"));
            this.workerGroup = new NioEventLoopGroup(cpuCount , new DefaultThreadFactory(initializer.getName() + "-NettyServer-WorkGroup"));
            this.bootstrap = new ServerBootstrap();

            this.bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class)
                    .handler(new LoggingHandler(LogLevel.INFO))
                    // 服务器通道配置
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 3000)                 // 连接超时
                    .option(ChannelOption.SO_BACKLOG, 1024)                             // 连接队列大小
                    .option(ChannelOption.SO_REUSEADDR, true)                           // 地址重用
                    .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)
                    // 客户端通道配置
                    .childOption(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)     // 内存池
                    .childOption(ChannelOption.SO_KEEPALIVE, true)                      // 保持连接
                    .childOption(ChannelOption.TCP_NODELAY, true)                       // 禁用Nagle算法
                    .childOption(ChannelOption.SO_RCVBUF, 1024 * 1024)                  // 接收缓冲区
                    .childOption(ChannelOption.SO_SNDBUF, 1024 * 1024)                  // 发送缓冲区
                    .childHandler(initializer);
            this.serverChannel = bootstrap.bind(port).sync().channel();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
//        log.info("NettyServer: start success , Port [{}]" , port);
    }

    /**
     * 关闭服务
     */
    public void shutdown() {
        if (serverChannel != null) {
            try{
                serverChannel.close();
                log.info("NettyServer: shutdown success");
            } catch (Exception e) {
                log.error("NettyServer: close error" , e);
            }
        }

        if (bossGroup != null) {
            bossGroup.shutdownGracefully();
        }
        if (workerGroup != null) {
            workerGroup.shutdownGracefully();
        }
    }

}
